package org.karelun.rabbit.bridge.ui.action;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.UnexecutableCommand;
import org.eclipse.emf.edit.command.CommandActionDelegate;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.karelun.rabbit.bridge.ITransactionEditingDomain;
import org.karelun.rabbit.bridge.ITransactionEditingDomainProvider;
import org.karelun.rabbit.bridge.TransactionAdapterFactoryEditingDomain;

public abstract class RabbitStaticSelectionCommandAction extends Action{
	
	protected ITransactionEditingDomain editingDomain;
	
	protected Command command;
	
	public RabbitStaticSelectionCommandAction(IWorkbenchPart workbenchPart){
		if(workbenchPart instanceof ITransactionEditingDomainProvider){
			editingDomain=((ITransactionEditingDomainProvider)workbenchPart).getTransactionEditingDomain();
		}
	}
	
	public RabbitStaticSelectionCommandAction(IEditorPart editorPart){
		this((IWorkbenchPart)editorPart);
	}
	
	public RabbitStaticSelectionCommandAction(ITransactionEditingDomain editingDomain){
		this.editingDomain=editingDomain;
	}
	
	public RabbitStaticSelectionCommandAction(){
	}
	
	 public void configureAction(ISelection selection)
	  {
	    // only handle structured selections
	    if (!(selection instanceof IStructuredSelection))
	    {
	      disable();
	    }
	    else
	    {
	      // convert the selection to a collection of the selected objects
	      IStructuredSelection sselection = (IStructuredSelection) selection;
	      List<?> list = sselection.toList();
	      Collection<Object> collection = new ArrayList<Object>(list);
	      
	      if(editingDomain==null){
	    	  for(Object object:collection){
	    		  editingDomain=TransactionAdapterFactoryEditingDomain.getTransactionEditingDomainFor(object);
	    		  if(editingDomain!=null){
	    			  break;
	    		  }
	    	  }
	      }
	      
	      // if we found an editing domain, create command
	      if (editingDomain != null)
	      {
	        command = createActionCommand(editingDomain, collection);
	        boolean readOnly = editingDomain.getCDOView().isReadOnly();
	        setEnabled(command.canExecute()&&!readOnly);
	      }

	      // give up if we couldn't create the command; otherwise, use a
	      // CommandActionDelegate to set the action's text, tool-tip, icon,
	      // etc. or just use the default icon
	      if (command == null || command == UnexecutableCommand.INSTANCE)
	      {
	        disable();
	      }
	      else if (!(command instanceof CommandActionDelegate))
	      {
	        if (getDefaultImageDescriptor() != null)
	        {
	          setImageDescriptor(getDefaultImageDescriptor());
	        }
	      }
	      else
	      {
	        CommandActionDelegate commandActionDelegate =
	          (CommandActionDelegate) command;

	        ImageDescriptor imageDescriptor =
	          objectToImageDescriptor(commandActionDelegate.getImage());
	        if (imageDescriptor != null)
	        {
	          setImageDescriptor(imageDescriptor);
	        }
	        else if (getDefaultImageDescriptor() != null)
	        {
	          setImageDescriptor(getDefaultImageDescriptor());
	        }

	        if (commandActionDelegate.getText() != null)
	        {
	          setText(commandActionDelegate.getText());
	        }
	        
	        if (commandActionDelegate.getDescription() != null)
	        {
	          setDescription(commandActionDelegate.getDescription());
	        }

	        if (commandActionDelegate.getToolTipText() != null)
	        {
	          setToolTipText(commandActionDelegate.getToolTipText());
	        }
	      }
	    }
	  }

	  protected abstract Command createActionCommand(ITransactionEditingDomain editingDomain,Collection<Object> collection);

	/**
	   * This can be overridden to provide the image descriptor used when the
	   * command does not provide one.  This implementation simply returns null.
	   */
	  protected ImageDescriptor getDefaultImageDescriptor()
	  {
	    return null;
	  }

	  /**
	   * This gets invoked when the selection is inappropriate or the command
	   * cannot be created.  It puts the action in the correct state for such
	   * error conditions.  This implementation disables the action and sets its
	   * icon to the default.
	   */
	  protected void disable()
	  {
	    setEnabled(false);
	    if (getDefaultImageDescriptor() != null)
	    {
	      setImageDescriptor(getDefaultImageDescriptor());
	    }
	  }

	  /**
	   * This executes the command.
	   */
	  @Override
	  public void run()
	  {
	    // this guard is for extra security, but should not be necessary
	    if (editingDomain != null && command != null)
	    {
	      // use up the command
	      editingDomain.getCommandStack().execute(command);
	    }
	  }

	  /**
	   * If necessary, this converts any image representation into an image
	   * descriptor.
	   */
	  protected ImageDescriptor objectToImageDescriptor(Object object)
	  {
	    return ExtendedImageRegistry.getInstance().getImageDescriptor(object);
	  }
}
